
using System;
using System.Collections.ObjectModel;
using FamilyTreeProject.Framework.Entities;
using System.Collections.Generic;
using System.Collections;

namespace FamilyTreeProject.Framework.Collections
{
    /// <summary>
    /// Represents a collection of objects that can be accessed by index (like
    /// a List) or by ID (like a Dictionary)
    /// </summary>
    /// <typeparam name="TType">The type of the items in the collection</typeparam>
    public class ObjectCollection<TType> : IObjectCollection<TType> where TType : IObjectBase
    {

        #region Private Fields

        private int ownerId;
        private IList<TType> items;
        private IDictionary<int, TType> lookupDictionary;

        #endregion

        #region Constructors

        /// <summary>
        /// Constructs an ObjectCollection
        /// </summary>
        /// <param name="ownerId">The Id of the Object that owns this Collection</param>
        public ObjectCollection(int ownerId)
        {
            this.ownerId = ownerId;
            items = new List<TType>();
            lookupDictionary = new Dictionary<int, TType>();
        }

        #endregion

        #region Private Members

        /// <summary>
        /// Adds the item to the Lookup Dictionary
        /// </summary>
        /// <param name="item">The item to add</param>
        private void AddItemToDictionary(TType item)
        {
            lookupDictionary.Add(item.Id, item);
        }

        /// <summary>
        /// Removes the item from the Lookup Dictionary
        /// </summary>
        /// <param name="item">The item to remove</param>
        private void RemoveItemFromDictionary(TType item)
        {
            lookupDictionary.Remove(item.Id);
        }

        #endregion

        #region IObjectCollection<TType>

        /// <summary>
        /// Determines whether the colelction contains an item with the specified key
        /// </summary>
        /// <param name="key">The key to check</param>
        /// <returns>A bbolean that indicates whether the colelction contains the specifed key</returns>
        public bool ContainsKey(int key)
        {
            return lookupDictionary.ContainsKey(key);
        }

        /// <summary>
        /// Gets the Lookup Dictionary
        /// </summary>
        public IDictionary<int, TType> Dictionary
        {
            get { return lookupDictionary; }
        }

        /// <summary>
        /// Gets the coolection of Items
        /// </summary>
        public IList<TType> Items
        {
            get { return items; }
        }

        /// <summary>
        /// Gets and sets the Id of the Object that owns the collection
        /// </summary>
        /// <returns>The Id</returns>
        public int OwnerId
        {
            get { return ownerId; }
            set { ownerId = value; }
        }

        /// <summary>
        /// Removes the item with the specified Key
        /// </summary>
        /// <param name="key">The key of the item to remove</param>
        public void Remove(int key)
        {
            items.Remove(lookupDictionary[key]);
            lookupDictionary.Remove(key);
        }

        #endregion

        #region IList<TType> Members

        /// <summary>
        /// Gets the Index in the List of a specific item
        /// </summary>
        /// <param name="item">The item whose index is required</param>
        /// <returns>The index of the item</returns>
        public int IndexOf(TType item)
        {
            return items.IndexOf(item);
        }

        /// <summary>
        /// Inserts an item at the specified index
        /// </summary>
        /// <param name="item">The item whose index is required</param>
        /// <param name="index">The index to insert the item at</param>
        public void Insert(int index, TType item)
        {
            items.Insert(index, item);
            AddItemToDictionary(item);
        }

        /// <summary>
        /// Removes the specified item from the list
        /// </summary>
        /// <param name="index">The index of the item being removed</param>
        /// <returns>The index of the item</returns>
        public void RemoveAt(int index)
        {
            RemoveItemFromDictionary(items[index]);
            items.RemoveAt(index);
        }

        /// <summary>
        /// Indexer for the List
        /// </summary>
        /// <param name="index">The index of the item</param>
        /// <returns>The item</returns>
        public TType this[int index]
        {
            get { return items[index]; }
            set { items[index] = value; }
        }

        #endregion

        #region ICollection<TType> Members

        /// <summary>
        /// Adds the specified item
        /// </summary>
        /// <param name="item">The item to be added</param>
        public void Add(TType item)
        {
            items.Add(item);
            AddItemToDictionary(item);
        }

        /// <summary>
        /// Clears the List
        /// </summary>
        public void Clear()
        {
            items.Clear();
            lookupDictionary.Clear();
        }

        /// <summary>
        /// Determines whether the List contains the specified item
        /// </summary>
        /// <param name="item">The item to be checked</param>
        /// <returns>A boolean indicating whether the item is the List</returns>
        public bool Contains(TType item)
        {
            return items.Contains(item);
        }

        /// <summary>
        /// Copies the List to an Array, starting at a specified index position
        /// </summary>
        /// <param name="array">The array to use</param>
        /// <param name="arrayIndex">The arrayIndex to start at.</param>
        public void CopyTo(TType[] array, int arrayIndex)
        {
            items.CopyTo(array, arrayIndex);
        }

        /// <summary>
        /// The number of items in the list
        /// </summary>
        /// <value>The number of items in the List</value>
        public int Count
        {
            get { return items.Count; }
        }

        /// <summary>
        /// A flag indicating whther the List is ReadOnly
        /// </summary>
        /// <value>A boolean indicating whether the List is ReadOnly</value>
        public bool IsReadOnly
        {
            get { return false; }
        }

        /// <summary>
        /// Removes the specified item
        /// </summary>
        /// <param name="item">The item to be removed</param>
        public bool Remove(TType item)
        {
            RemoveItemFromDictionary(item);
            return items.Remove(item);
        }

        #endregion

        #region IEnumerable<TType> Members

        /// <summary>
        /// Gets an Enumerator for the List
        /// </summary>
        /// <returns>The enumerator (IEnumerator<TType>)</returns>
        public IEnumerator<TType> GetEnumerator()
        {
            return items.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        /// <summary>
        /// Gets an Enumerator for the List
        /// </summary>
        /// <returns>The enumerator (IEnumerator)</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return items.GetEnumerator();
        }

        #endregion

    }
}
